using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

namespace GeYiHome.PublicLibrary.Rules
{
    /// <summary>
    /// 规则生成
    /// </summary>
    public class RuleBuilder
    {
        private object _member;
        private readonly object _compiled;
        private readonly object _source;

        private readonly bool _isCheckMember;
        internal RuleBuilder(object source)
        {
            _source = source;
            _isCheckMember = false;
        }

        internal RuleBuilder(object member, object compiled)
        {
            _member = member;
            _compiled = compiled;
            _isCheckMember = true;
        }

        private object Member => _isCheckMember ? _compiled : _source;


        public void Throw<T>(T baseException)
        {
            throw baseException is Exception ? baseException as Exception : new OpenApiException<T>(baseException);
        }

        public RuleBuilder NotNull<T>(T baseException)
        {
            if (Member==null) Throw(baseException);
            return this;
        }

        /// <summary>
        /// 非空验证
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="baseException"></param>
        public RuleBuilder NotNullOrEmpty<T>(T baseException)
        {
            NotNull(baseException);
            if (Member is Guid)
                if (((Guid)Member)==Guid.Empty) Throw(baseException);
            if (Member is string)
                if (string.IsNullOrWhiteSpace(Member.ToString())) Throw(baseException);
            if (Member is ICollection)
                if (((ICollection)Member).Count == 0) Throw(baseException);
            return this;
        }

        /// <summary>
        /// 判断是否不相同
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="arg"></param>
        /// <param name="baseException"></param>
        public RuleBuilder NotEquals<T>(object arg, T baseException)
        {
            if (!Member.Equals(arg)) Throw(baseException);
            return this;
        }
        /// <summary>
        /// 判断是否相同
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="arg"></param>
        /// <param name="baseException"></param>
        public RuleBuilder Equals<T>(object arg, T baseException)
        {
            if (Member.Equals(arg)) Throw(baseException);
            return this;
        }

        #region LessThan
        public RuleBuilder LessThan<T>(DateTime arg, T baseException)
        {
            if ((DateTime)Member < arg) Throw(baseException);
            return this;
        }

        public RuleBuilder LessThan<T>(int arg, T baseException)
        {
            if ((int)Member < arg) Throw(baseException);
            return this;
        }
        public RuleBuilder LessThan<T>(long arg, T baseException)
        {
            if ((long)Member < arg) Throw(baseException);
            return this;
        }
        public RuleBuilder LessThan<T>(float arg, T baseException)
        {
            if ((float)Member < arg) Throw(baseException);
            return this;
        }
        public RuleBuilder LessThan<T>(decimal arg, T baseException)
        {
            if ((decimal)Member < arg) Throw(baseException);
            return this;
        }
        #endregion

        #region GreaterThan
        public RuleBuilder GreaterThan<T>(DateTime arg, T baseException)
        {
            if ((DateTime)Member > arg) Throw(baseException);
            return this;
        }
        public RuleBuilder GreaterThan<T>(int arg, T baseException)
        {
            if ((int)Member > arg) Throw(baseException);
            return this;
        }
        public RuleBuilder GreaterThan<T>(long arg, T baseException)
        {
            if ((long)Member > arg) Throw(baseException);
            return this;
        }
        public RuleBuilder GreaterThan<T>(float arg, T baseException)
        {
            if ((float)Member > arg) Throw(baseException);
            return this;
        }
        public RuleBuilder GreaterThan<T>(decimal arg, T baseException)
        {
            if ((decimal)Member > arg) Throw(baseException);
            return this;
        }
        #endregion

        /// <summary>
        /// 字符串长度验证
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="minException"></param>
        /// <param name="maxException"></param>
        /// <param name="min"></param>
        /// <param name="max"></param>
        public RuleBuilder Length<T>(T minException, T maxException, int min = 0, int max = 4000)
        {
            if (Member.ToString().Length < min)
                Throw(minException);
            if (Member.ToString().Length > max)
                Throw(maxException);
            return this;
        }
        /// <summary>
        /// 判断是否为真
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="baseException"></param>
        public RuleBuilder NotTrue<T>(T baseException)
        {
            if (!Convert.ToBoolean(Member)) Throw(baseException);
            return this;
        }

        /// <summary>
        /// 检测内容是否为空
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="TOut"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="expression"></param>
        /// <param name="baseException"></param>
        public RuleBuilder NotNullOrEmptyForAll<TSource, TOut, T>(Expression<Func<TSource, TOut>> expression, T baseException)
        {
            var members = Member as ICollection<TSource>;
            if (members!=null)
            {
                var ls = members;
                ls.ForEach(p =>
                {
                    p.Valid().NotNullOrEmpty(baseException);
                });
            }
            else
            {
                Throw(baseException);
            }
            return this;
        }
        /// <summary>
        /// 检测内容是否为真,如果判断为真，则抛出指定异常
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="expression">如果判断为真，则抛出指定异常</param>
        /// <param name="baseException"></param>
        /// <returns></returns>
        public RuleBuilder NotTrueForAll<TSource, T>(Expression<Func<TSource, bool>> expression, T baseException)
        {
            var members = Member as ICollection<TSource>;
            if (members!=null)
            {
                var ls = members;
                ls.ForEach(p =>
                {
                    p.Valid().NotNull(baseException);
                });
                var resutl = ls.Where(expression.Compile());
                if (resutl.Any()) Throw(baseException);
            }
            else
            {
                Throw(baseException);
            }
            return this;
        }
    }
}
